import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;

public class CodeEdit extends JScrollPane {
    private class LineNoListModel extends AbstractListModel<Integer> {
        private int size;
        public void setSize(int size) {
            int oldSize = this.size;
            this.size = size;
            if (oldSize > size) {
                fireIntervalRemoved(this, size, oldSize - 1);
            } else if (oldSize < size) {
                fireIntervalAdded(this, oldSize, size - 1);
            }
        }
        @Override
        public int getSize() {
            return size;
        }
        @Override
        public Integer getElementAt(int index) {
            return index + 1;
        }
    }
    private class LineNumListCellRenderer extends JLabel implements ListCellRenderer<Integer> {
        @Override
        public Component getListCellRendererComponent(JList<? extends Integer> list, Integer value, int index, boolean isSelected, boolean cellHasFocus) {
            setText("" + value);
            return this;
        }
    }
    private JTextPane ta = new JTextPane();
    private Font f = FileUtil.loadFont("consolas.ttf", 18);
    private LineNoListModel listLineNoModel = new LineNoListModel();
    private JList<Integer> listLineNo = new JList<>(listLineNoModel);
    private LineNumListCellRenderer listLineNoRenderer = new LineNumListCellRenderer();
    private File file;
    private void updateLineCount(int lines) {
        listLineNoModel.setSize(lines);
        if (lines > 0) {
            FontMetrics metrics = listLineNo.getFontMetrics(f);
            int maxNumStringLength = Integer.toString(lines).length();
            int width = (int) (metrics.charWidth('a') * maxNumStringLength + 0.5) + 5; // 等宽字体所有字符宽度相等
            listLineNo.setFixedCellWidth(width);
        }
    }
    public CodeEdit(File file) {
        this.file = file;
        setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        setViewportView(ta);
        setRowHeaderView(listLineNo);
        listLineNoRenderer.setFont(f);
        listLineNo.setFixedCellWidth(38);
        listLineNo.setBackground(Color.LIGHT_GRAY);
        listLineNo.setCellRenderer(listLineNoRenderer);
        listLineNo.setFont(f);
        ta.setFont(f);
        ta.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void removeUpdate(DocumentEvent e) {
                int lines = ta.getDocument().getDefaultRootElement().getElementCount();
                updateLineCount(lines);
            }
            @Override
            public void insertUpdate(DocumentEvent e) {
                int lines = ta.getDocument().getDefaultRootElement().getElementCount();
                updateLineCount(lines);
            }
            @Override
            public void changedUpdate(DocumentEvent e) {
                int lines = ta.getDocument().getDefaultRootElement().getElementCount();
                updateLineCount(lines);
            }
        });
    }
    public String getText() {
        try {
            int length = ta.getDocument().getLength();
            return ta.getDocument().getText(0, length);
        } catch (Exception ex) {
            return null;
        }
    }
    public void setText(String str) {
        ta.setText(str);
    }
    public File getFile() {
        return file;
    }
    public void setFile(File file) {
        this.file = file;
    }
    public Font getTextAreaFont() {
        return this.f;
    }
    public void setTextAreaFont(Font f) {
        ta.setFont(f);
        listLineNoRenderer.setFont(f);
        this.f = f;
        updateLineCount(ta.getDocument().getDefaultRootElement().getElementCount());
    }
    public int getCaretPosition() {
        return ta.getCaretPosition();
    }
    public void setCaretPosition(int i) {
        ta.setCaretPosition(i);
    }
    public String getSelectedText() {
        return ta.getSelectedText();
    }
    public void select(int start, int end) {
        ta.select(start, end);
    }
    public void requestFocus() {
        ta.requestFocus();
    }
    public void replaceSelection(String text) {
        ta.replaceSelection(text);
    }
}